package interfaces;

import java.util.Vector;

import sun.reflect.generics.reflectiveObjects.NotImplementedException;
import datastructures.Vector2f;
import exceptions.Exception;
import gameclasses.GameManager;
import gameclasses.Map;
import helperclasses.IDGenerator;

/**
 * Abstract class for Units. 
 * 
 * @version 0.4.1
 * @since 0.1.0
 * @author Tim
 *
 */
public abstract class IUnit implements IHitable, IShooter, IMovable {
	
	public static final int TYPE_LAND = -101;
	public static final int TYPE_WATER = -102;
	public static final int TYPE_AMPHIBIOUS = -103;
	public static final int TYPE_AIR = -104;
	
	protected GameManager gm;
	protected Map map;
	protected final int playerID;
	protected Vector2f position;
	protected final int maxHitPoints;
	protected int hitPoints;
	protected final int attackPoints;
	protected final int price;
	protected final long ID;
	protected final double speed;
	protected final double shootrange;
	protected final double maxFuelAmount;
	protected final double fuelUsage;
	protected double currentFuel;
	protected final int maxAmmo;
	protected int ammoCount;
	protected final int vehicletype;
	
	protected IUnit(GameManager gm, int playerID, Vector2f position, int hitPoints, int attackPoints, int price, 
			double speed, double shootrange, double maxFuelAmount, double fuelUsage, int maxAmmo, int vehicletype) {
		this.gm = gm;
		this.playerID = playerID;
		this.position = position;
		this.maxHitPoints = hitPoints;
		this.hitPoints = hitPoints;
		this.attackPoints = attackPoints;
		this.price = price;
		this.ID = IDGenerator.getID();
		this.speed = speed;
		this.shootrange = shootrange;
		this.maxFuelAmount = maxFuelAmount;
		this.currentFuel = maxFuelAmount;
		this.fuelUsage = fuelUsage;
		this.map = gm.getMap();
		this.ammoCount = maxAmmo;
		this.maxAmmo = maxAmmo;
		this.vehicletype = vehicletype;
	}

	public int getPlayerID() {
		return playerID;
	}

	public int getPrice() {
		return price;
	}
	
	@Override
	public Vector2f getPosition() {
		return position;
	}

	@Override
	public int getHitPoints() {
		return hitPoints;
	}

	@Override
	public int getAttackPoints() {
		return attackPoints;
	}

	@Override
	public int getAmmoCount() 
	{
		return ammoCount;
	};
	
	public int getVehicleType()
	{
		return this.vehicletype;
	}
	
	@Override
	public int resupply(int amount) 
	{
		ammoCount+=amount;
		if (ammoCount>maxAmmo)
		{
			int load = amount - (ammoCount-maxAmmo);
			ammoCount = maxAmmo;
			return load;
		}
		else
		{
			return amount;
		}
	};


	@Override
	public int shoot(IHitable unit){
		
		if (ammoCount<1)
		{
			return Exception.OUT_OF_AMMO;
		}
		
		if (getDistanceTo(unit)<=shootrange)
		{
			ammoCount--;
			return unit.hit(attackPoints);
		}
		return Exception.TARGET_OUT_OF_RANGE;
	}
	
	@Override
	public int hit(int attackpoints) {
		hitPoints -= attackpoints;

		if (hitPoints < 0) {
			gm.removeUnit(this);
			return Exception.TARGET_DESTROYED;
		}
		return Exception.TARGET_HIT;

	}

	@Override
	public int repair(int amount) {
		hitPoints+=amount;
		if (hitPoints>maxHitPoints)
		{
			int load = amount - (hitPoints-maxHitPoints);
			ammoCount = maxHitPoints;
			return load;
		}
		else
		{
			return amount;
		}
	}

	public long getID() {
		return ID;
	}

	public String getStatus() {
		return "ID:" + ID + " HP: " + hitPoints + "/" + maxHitPoints
				+ " Pos: (" + position.x() + "|" + position.y() + ")";
	}

	@Override
	public double getShootRange() {
		return shootrange;
	}

	@Override
	public double getRange() {
		return speed;
	}

	@Override
	public double getFuelAmount() {
		return currentFuel;
	}

	@Override
	public double refuel(double amount) {
		currentFuel += amount;
		
		if (currentFuel > maxFuelAmount)
		{
			double load = amount - (currentFuel-maxFuelAmount);
			currentFuel = maxFuelAmount;
			return load;
		}
		else
		{
			return amount;
		}
	}

	@Override
	public double getDistanceTo(IHitable target) {
		Vector2f t = target.getPosition();
		return map.getDistanceBetweenPoints(this.position, t);
	}
	
	@Override
	public int move(Vector2f p) {
		// TODO Auto-generated method stub
		return 0;
	}
	
	@Override
	public void appendWaypoints(Vector<Vector2f> waypoints) throws NotImplementedException {
		throw new NotImplementedException();
	}

	@Override
	public Vector<Vector2f> getWaypoints() throws NotImplementedException {
		throw new NotImplementedException();
	}
	
	@Override
	public void setWaypoints(Vector<Vector2f> waypoints) throws NotImplementedException {
		throw new NotImplementedException();	
	}
}
